﻿using System;
using System.Collections.Generic;
using System.Linq;
using GigaSite.Domain.Entities;
using GigaSite.Domain.Enums;
using GigaSite.Domain.Interfaces.Repositories;

namespace GigaSite.Domain.DAL.Repositories
{
    /// <summary>
    /// СУБД Реализация
    /// </summary>
    public class BusinessCardsRepository: BaseRepository<BusinessCard>, IBusinessCardsRepository
    {
        /// <summary>
        /// Репозиторий изображений для работы с визитками
        /// </summary>
        public IImagesRepository ImagesRepository { get; set; }

        /// <summary>
        /// Стандартный конструктор
        /// </summary>
        /// <param name="dataContext">Контекст данных</param>
        /// <param name="imagesRepository">Репозиторий изображений</param>
        public BusinessCardsRepository(GigaDataContext dataContext, IImagesRepository imagesRepository) : base(dataContext)
        {
            ImagesRepository = imagesRepository;
        }

        /// <summary>
        /// Загружает указанную сущность по ее идентификатору
        /// </summary>
        /// <param name="id">Идентификатор сущности</param>
        /// <returns>Сущность с указанным идентификатором или Null</returns>
        public override BusinessCard Load(long id)
        {
            return Find(c => c.Id == id);
        }

        /// <summary>
        /// Добавляет визитку к указанному пользователю в визитницу
        /// </summary>
        /// <param name="user">Пользователь</param>
        /// <param name="card">Визитка</param>
        /// <param name="mappingType">Тип владельчества, по умолчанию, визитка добавляется просто в визитницу</param>
        public void AddBusinessCardToUser(User user, BusinessCard card, BusinessCardMappingTypes mappingType = BusinessCardMappingTypes.Holder)
        {
            // Ищем есть ли маппинг на эту визитку
            var mapping =
                DataContext.BusinessCardToUserMappings.FirstOrDefault(m => m.BusinessCard == card && m.User == user);
            if (mapping != null)
            {
                // Обновляем его
                mapping.MappingType = mappingType;
                mapping.DateModified = DateTime.Now;
            }
            else
            {
                // Создаем маппинг
                mapping = new BusinessCardToUserMapping()
                              {
                                  BusinessCard = card,
                                  User = user,
                                  MappingType = mappingType,
                                  DateCreated = DateTime.Now
                              };
                DataContext.BusinessCardToUserMappings.InsertOnSubmit(mapping);
            }
        }

        /// <summary>
        /// Убирает указанную визитку из визитницы пользователя
        /// </summary>
        /// <param name="user">Пользователь</param>
        /// <param name="card">Визитка</param>
        public void RemoveBusinessCardFromUser(User user, BusinessCard card)
        {
            // Ищем есть ли маппинг на эту визитку
            var mapping =
                DataContext.BusinessCardToUserMappings.FirstOrDefault(m => m.BusinessCard == card && m.User == user);
            if (mapping != null)
            {
                DataContext.BusinessCardToUserMappings.DeleteOnSubmit(mapping);
            }
        }

        /// <summary>
        /// Удаляет сущность из репозитория
        /// </summary>
        /// <param name="entity">Сущность для удаления</param>
        public override void Delete(BusinessCard entity)
        {
            // Удаляем так же картинку которая связана с этой визиткой
            var image = ImagesRepository.GetImage(entity.ImageURI);
            if (image != null)
            {
                ImagesRepository.Delete(image);
            }
            base.Delete(entity);
        }

        /// <summary>
        /// Добавляет указанную визитку в указанную категорию
        /// </summary>
        /// <param name="card">Визитка</param>
        /// <param name="category">Категория</param>
        public void AddBusinessCardToCategory(BusinessCard card, Category category)
        {
            // Ищем маппинг на эту визитку
            var mapping =
                DataContext.BusinessCardToCategoryMappings.FirstOrDefault(
                    m => m.BusinessCard == card && m.Category == category);
            if (mapping != null)
            {
                return;
            }
            // Создаем маппинг
            mapping = new BusinessCardToCategoryMapping()
                          {
                              BusinessCard = card,
                              Category = category,
                              DateCreated = DateTime.Now

                          };
            DataContext.BusinessCardToCategoryMappings.InsertOnSubmit(mapping);
        }

        /// <summary>
        /// Убирает указаную визитку из указанной категории
        /// </summary>
        /// <param name="card">Визитка</param>
        /// <param name="category">Категория</param>
        public void RemoveBusinessCardFromCategory(BusinessCard card, Category category)
        {
            // Ищем маппинг на эту визитку
            var mapping =
                DataContext.BusinessCardToCategoryMappings.FirstOrDefault(
                    m => m.BusinessCard == card && m.Category == category);
            if (mapping != null)
            {
                DataContext.BusinessCardToCategoryMappings.DeleteOnSubmit(mapping);
            }
        }

        /// <summary>
        /// Возвращает количество визиток, находящихся в указанной категории, включая все дочерние категории
        /// </summary>
        /// <param name="category">Категория</param>
        /// <returns></returns>
        public int GetCardsCountInCategory(Category category)
        {
            // Строим список всех элементов в категориях
            IList<Category> allCategories = new List<Category>()
                                                {
                                                    category
                                                };
            category.GetAllChildCategories(ref allCategories);

            // Считаем
            return allCategories.Sum(cat => cat.BusinessCardToCategoryMappings.Count);

            // TODO: переделать на выборку средствами БД
        }

        /// <summary>
        /// Возвращает все визитки, находящиеся в указанной категории, включая дочерние категории
        /// </summary>
        /// <param name="category">Категория</param>
        /// <returns>Коллекция визиток в категории</returns>
        public IEnumerable<BusinessCard> GetAllCardsInCategory(Category category)
        {
            // строим список всех подкатегорий в категории
            IList<Category> allChildCategories = new List<Category>()
                                                     {
                                                         category
                                                     };
            category.GetAllChildCategories(ref allChildCategories);

            // выбираем используя монаду SelectMany
            return from cat in allChildCategories
                   from mapping in cat.BusinessCardToCategoryMappings
                   select mapping.BusinessCard;

            // TODO: переделать на выборку средствами БД
        }
    }
}